#ifndef __TABLE_H__
#define __TABLE_H__

// export keyword is not supported by VC++ unfortunatly

/**
 *  @file
 *  Class "Table"
 */

/**
 * Class Template for a Table of Element
 *
 */
template <typename T>
class Table
{
public:
	Table();
	~Table();
	Table(unsigned int m, unsigned int n);

	Table<T>&	operator=(const Table& rhs);
	T&			operator()(unsigned int m, unsigned int n);

	unsigned int numRows();
	unsigned int numCols();

	void resize(unsigned int m, unsigned int n, const T& value);
	void resize(unsigned int m, unsigned int n);



private:
	void destroy();

	unsigned int	m_NumRows;		//!< number of rows
	unsigned int	m_NumCols;		//!< number of columns
	T**				m_DataMatrix;	//!< Matrix of Elements
};


/**
 * Constructor
 *
 */
template <typename T>
Table<T>::Table()
{
	m_DataMatrix = 0;
	m_NumRows = 0;
	m_NumCols = 0;
}


/**
 * Constructor with a certain size
 * @param unsigned int m - width of the table
 * @param unsigned int n - height of the table
 */
template <typename T>
Table<T>::Table(unsigned int m, unsigned int n)
{
	m_DataMatrix = 0;
	m_NumRows = 0;
	m_NumCols = 0;
	resize(m, n, T());
}


/**
 * Destructor
 *
 *
 */
template <typename T>
Table<T>::~Table()
{
	destroy();
}


/**
 * Empty the Table
 * @param void
 * @return void
 */
template <typename T>
void Table<T>::destroy()
{
	if (m_DataMatrix)
	{
		for (unsigned int i = 0; i < m_NumCols; ++i)
		{
			if (m_DataMatrix[i])
			{
				delete[] m_DataMatrix[i];
				m_DataMatrix[i] = 0;
			}
		}
		delete[] m_DataMatrix;
		m_DataMatrix = 0;
	}
	m_NumRows = 0;
	m_NumCols = 0;
}


/**
 * Resize the Table. All elements are reset
 * @param unsigned int m - width of the Table
 * @param unsigned int n - height of the Table
 * @return void
 */
template <typename T>
void Table<T>::resize(unsigned int m, unsigned int n)
{
	resize(m, n, T());
}

/**
 * Resize the Table. All elements are set to a value
 * @param int m - width of the Table
 * @param int n - height of the Table
 * @param const T& value - value to resize the Table with
 * @return void
 */
template <typename T>
void Table<T>::resize(unsigned int m, unsigned int n, const T& value)
{
	destroy();
	m_NumCols = m; // x
	m_NumRows = n; // y
	m_DataMatrix = new T*[m_NumCols];

	for (unsigned int i = 0; i < m_NumCols; ++i)
	{
		m_DataMatrix[i] = new T[m_NumRows];
		for (unsigned int j = 0; j < m_NumRows; ++j)
		{
			m_DataMatrix[i][j] = value;
		}
	}
}


/**
 * Return element at a specific location
 * @param int m - coordinate x
 * @param int n - coordinate y
 * @return T& - Element
 */
template <typename T>
T& Table<T>::operator() (unsigned int m, unsigned int n)
{
	return m_DataMatrix[m][n];
}


/**
 * Return number of Rows
 * @param void
 * @return unsigned int -
 */
template <typename T>
unsigned int Table<T>::numRows()
{
	return m_NumRows;
}


/**
 * Return number of Columns
 * @param void
 * @return unsigned int -
 */
template <typename T>
unsigned int Table<T>::numCols()
{
	return m_NumCols;
}



#endif // __TABLE_H__